﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

using ABCat.Core;
using ABCat.Core.Plugins;
using ABCat.Core.Plugins.DataProviders;
using ABCat.Core.Plugins.DataSets;
using ABCat.Shared;
using ABCat.Shared.Properties;

namespace ABCat.Plugins.DataSources.AudioBooks
{
	[PluginCreator("AudioBooks DbContainer on SQLite.Net ORM", WorkModeEnum.PerCall),
	UsedImplicitly]
	public class AudioBooksDbContainerSQLite : IDbContainer
	{
		#region + Events +

		public event EventHandler Disposed;

		#endregion
		#region + Fields +

		private readonly Lazy<AudioBookSet> _audioBooks;
		private readonly Lazy<BinaryDataSet> _binaryDataSet;
		private readonly HashSet<string> _recordsCache = new HashSet<string>();
		private readonly Lazy<ReplacementStringSet> _replacementStringSet;
		private readonly Lazy<UserDataSet> _userDataSet;
		private readonly Queue<string> _waitForParse = new Queue<string>();

		private AudioBooksDbContainerSQLiteConfig _config;

		#endregion
		#region + Properties +

		public IAudioBookGroupSet AudioBookGroupSet
		{
			get { return (IAudioBookGroupSet)AudioBookSet; }
		}

		public IAudioBookSet AudioBookSet
		{
			get { return _audioBooks.Value; }
		}

		public bool AutoSaveChanges		{get; set;}
		public IBinaryDataSet BinaryDataSet
		{
			get
			{
				return _binaryDataSet.Value;
			}
		}

		public Config Config		{get; set;}
		public Context Context		{get; private set;}
		public IHiddenRecordSet HiddenRecordSet
		{
			get { return (IHiddenRecordSet)UserDataSet; }
		}

		public IHiddenValueSet HiddenValueSet
		{
			get { return (IHiddenValueSet)UserDataSet; }
		}


		public HashSet<string> RecordsCache
		{
			get { return _recordsCache; }
		}

		public IReplacementStringSet ReplacementStringSet
		{
			get { return _replacementStringSet.Value; }
		}

		public IUserDataSet UserDataSet
		{
			get { return _userDataSet.Value; }
		}

		public Queue<string> WaitForParse
		{
			get { return _waitForParse; }
		}

		#endregion
		#region + Ctor +

		public AudioBooksDbContainerSQLite([NotNull] Context context)
		{
			Context = context;
			_audioBooks = new Lazy<AudioBookSet>(() =>
				{
					bool needVacuum = (_config.LastAudioBooksVacuum.AddDays(3) < DateTime.Now);
					var result = new AudioBookSet(_config.AudioBooksFilePath, AudioBooksDbContainerSQLiteConfig.LockContext, needVacuum);
					if (needVacuum)
					{
						lock (AudioBooksDbContainerSQLiteConfig.LockContext)
						{
							_config.LastAudioBooksVacuum = DateTime.Now;
							_config.Save();
						}
					}
					return result;
				}, true);
			_replacementStringSet = new Lazy<ReplacementStringSet>(() => new ReplacementStringSet(_config.ProcessingSettingsFilePath, AudioBooksDbContainerSQLiteConfig.LockContext), true);
			_userDataSet = new Lazy<UserDataSet>(() => new UserDataSet(_config.UserDataFilePath, AudioBooksDbContainerSQLiteConfig.LockContext), true);
			_binaryDataSet = new Lazy<BinaryDataSet>(() => new BinaryDataSet(_config.BinaryDataFilePath, AudioBooksDbContainerSQLiteConfig.LockContext), true);
		}

		#endregion
		#region + Logic +

		public bool CheckForConfig(bool correct, out Config incorrectConfig)
		{
			_config = Config.Load<AudioBooksDbContainerSQLiteConfig>(Context);
			var configCheckResult = _config.Check(correct);
			incorrectConfig = configCheckResult ? null : _config;
			return configCheckResult;
		}

		public void Dispose()
		{
			if (AutoSaveChanges) SaveChanges();
			Disposed.Fire(this);
		}

		public void SaveChanges()
		{
			AudioBookSet.SaveAudioBooks();
			AudioBookGroupSet.SaveAudioBookGroups();
			BinaryDataSet.SaveBinaryData();
		}

		#endregion
	}
}